package de.uhlesoluschns.opensearch.provider;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.LiveFolders;
import de.uhlesoluschns.opensearch.OpenSearch;
import de.uhlesoluschns.opensearch.OpenSearch.Provider;
import de.uhlesoluschns.opensearch.OpenSearch.ProviderLiveFolder;
import de.uhlesoluschns.opensearch.OpenSearch.Suggestion;

public class OpenSearchProvider extends ContentProvider {
	
	private static final UriMatcher matcher;
	private static final Map<String, String> ENGINE_LIVE_FOLDER_PROJECTION_MAP;
	private static final int SEARCH_ENGINE_DIR = 0;
	private static final int SEARCH_ENGINE_ITEM = 1;
	private static final int SEARCH_ENGINE_LIVE = 3;
	
	private static final int SEARCH_SUGGESTION = 10;
	
	private static final int HTTP_TIMEOUT_MS = 1000;
	private static final String HTTP_TIMEOUT = "http.connection-manager.timeout";
	
	static {
		matcher = new UriMatcher(UriMatcher.NO_MATCH);
		matcher.addURI(OpenSearch.AUTHORITY, Provider.PATH, SEARCH_ENGINE_DIR);
		matcher.addURI(OpenSearch.AUTHORITY, Provider.PATH + "/#", SEARCH_ENGINE_ITEM);
		matcher.addURI(OpenSearch.AUTHORITY, ProviderLiveFolder.PATH, SEARCH_ENGINE_LIVE);
		
		matcher.addURI(OpenSearch.AUTHORITY, Suggestion.PATH + "/#", SEARCH_SUGGESTION);
		
		
		ENGINE_LIVE_FOLDER_PROJECTION_MAP = new HashMap<String, String>();
		ENGINE_LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders._ID, ProviderLiveFolder.COL_ID);
		ENGINE_LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.NAME, ProviderLiveFolder.COL_SHORT_NAME);
		ENGINE_LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.DESCRIPTION, ProviderLiveFolder.COL_DESCRIPTION);
		ENGINE_LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.ICON_BITMAP, ProviderLiveFolder.COL_IMAGE);
	}
	
//	private static ArrayListCursor makeEmptyCursor() {
//		return new ArrayListCursor(null, new ArrayList<ArrayList>());
//	}
	
	
	private DatabaseHelper db;
	private HttpClient httpClient;
	
	@Override
	public boolean onCreate() {
		db = new DatabaseHelper(getContext());
		httpClient = new DefaultHttpClient();
		httpClient.getParams().setLongParameter(HTTP_TIMEOUT, HTTP_TIMEOUT_MS);
		return true;
	}
	
	@Override
	public String getType(Uri uri) {
		System.out.println("Provider.getType()");
		System.out.println(uri);
		switch(matcher.match(uri)) {
		case SEARCH_ENGINE_DIR:
		case SEARCH_ENGINE_LIVE:
			return Provider.CONTENT_DIR;
		case SEARCH_ENGINE_ITEM:
			return Provider.CONTENT_ITEM;
		case SEARCH_SUGGESTION:
			System.out.println("OpenSearchProvider.getType() :: SUGGESTION");
			return Suggestion.CONTENT_DIR;
		}
		return null; //"application/opensearchdescription+xml";
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		switch(matcher.match(uri)) {
		case SEARCH_ENGINE_DIR:
			if(selection != null) {
				return db.getWritableDatabase().delete(Provider.TABLE_NAME, selection, selectionArgs);
			}
			break;
		}
		return 0;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		switch(matcher.match(uri)) {
		case SEARCH_ENGINE_DIR:
			long ret = db.getWritableDatabase().insert(Provider.TABLE_NAME, null, values);
			return Uri.withAppendedPath(uri, "" + ret);
		}
		return null;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		switch(matcher.match(uri)) {
		case SEARCH_ENGINE_DIR:
			return db.getReadableDatabase().query(Provider.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
		case SEARCH_ENGINE_ITEM:
			return db.getReadableDatabase().query(Provider.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
		case SEARCH_ENGINE_LIVE:
			SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
			qb.setTables(Provider.TABLE_NAME);
			qb.setProjectionMap(ENGINE_LIVE_FOLDER_PROJECTION_MAP);
			Cursor cursor = qb.query(db.getReadableDatabase(), projection, null, null, null, null, Provider.COL_SHORT_NAME);
			cursor.setNotificationUri(getContext().getContentResolver(), uri);
			return cursor; 
		case SEARCH_SUGGESTION:
			try {
				return getSuggestion(uri, selection);
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}
	
	private Cursor getSuggestion(Uri uri, String query) throws ClientProtocolException, IOException, ParseException, JSONException {
		int engineId = Integer.parseInt(uri.getLastPathSegment());
		//TODO cache
		
		Cursor engine = db.getReadableDatabase().query(Provider.TABLE_NAME, 
				new String [] {Provider.COL_INPUT_ENCODING, Provider.COL_SUGGESTION_URL}, 
				"_id=?", new String [] {"" + engineId}, null, null, null);

		if(engine.moveToFirst()) {
			query = URLEncoder.encode(query, engine.getString(0));
			String url = String.format(engine.getString(1), query);
			System.out.println(url);
			
			HttpGet method = new HttpGet(url);
			HttpResponse response = httpClient.execute(method);
			
			if(response.getStatusLine().getStatusCode() == 200) {
				JSONArray results = new JSONArray(EntityUtils.toString(response.getEntity()));
				return new SuggestionsCursor(results.getJSONArray(1));
			}
		}
		engine.close();
		
		return null;
	}

}
